package v3

import (
	"github.com/AsynkronIT/protoactor-go/actor"

	nproto "nggs/network/protocol"
)

type MessageHandler func(iRecv IMessage, iSend IMessage, ctx actor.Context, args ...interface{})

type IMessageDispatcher interface {
	Register(id MessageID, handler MessageHandler) (err error)
	Dispatch(iRecv IMessage, iSend IMessage, ctx actor.Context, args ...interface{}) (err error)
}

type oneMessageDispatcher struct {
	Handler MessageHandler
}

type messageDispatcher struct {
	Dispatchers map[MessageID]*oneMessageDispatcher
}

func NewMessageDispatcher() IMessageDispatcher {
	return &messageDispatcher{
		Dispatchers: map[MessageID]*oneMessageDispatcher{},
	}
}

func (mgr *messageDispatcher) Register(id MessageID, handler MessageHandler) (err error) {
	_, ok := mgr.Dispatchers[id]
	if ok {
		return &nproto.ErrDispatcherAlreadyRegister{MessageID: id}
	}
	mgr.Dispatchers[id] = &oneMessageDispatcher{
		Handler: handler,
	}
	return
}

func (mgr *messageDispatcher) Dispatch(iRecv IMessage, iSend IMessage, ctx actor.Context, args ...interface{}) (err error) {
	messageID := iRecv.Head().MessageID

	dispatcher, ok := mgr.Dispatchers[messageID]
	if !ok {
		err = &nproto.ErrNoDispatcher{MessageID: messageID}
		return
	}

	dispatcher.Handler(iRecv, iSend, ctx, args...)

	return
}
